package cn.tinkling.youdao;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.eclipse.swt.widgets.Display;

public class YoudaoDictionary {

	private static final String BasicURL = "http://fanyi.youdao.com/openapi.do?keyfrom=Tinkling&key=1977836024&type=data&doctype=json&version=1.1&q=";

	private int mHistoriesSize = 20;

	private final LruCache<String, YouDaoResult> mCache = new LruCache<String, YouDaoResult>(50);
	private final LinkedList<String> mHistories = new LinkedList<String>();
	private final ExecutorService mExecutorService = Executors.newFixedThreadPool(5, new ThreadFactory() {

		@Override
		public Thread newThread(Runnable r) {
			Thread thread = new Thread(r);
			thread.setPriority(Thread.NORM_PRIORITY - 1);
			return thread;
		}
	});

	public void search(Display display, String query, Callbacks callbacks) {
		search(display, query, callbacks, false);
	}

	public void search(Display display, String query, Callbacks callbacks, boolean fromHistorie) {
		if (query == null || query.trim().length() == 0)
			return;

		if (!fromHistorie) {
			mHistories.remove(query);
			mHistories.add(0, query);

			if (mHistories.size() > mHistoriesSize) {
				mHistories.remove(mHistoriesSize - 1);
			}
		}

		YouDaoResult cache = mCache.get(query);
		if (cache != null) {
			if (callbacks != null) {
				callbacks.onHandlQuery(query, cache);
			}
		} else {
			mExecutorService.submit(new QueryRequest(display, query, callbacks));
		}
	}

	public YouDaoResult getCache(String query) {
		return mCache.get(query);
	}

	public LinkedList<String> getHistories() {
		return mHistories;
	}

	public void shutdown() {
		mExecutorService.shutdown();
	}

	private final class QueryRequest implements Runnable {

		private final Display mDisplay;
		private final String mQuery;
		private final Callbacks mCallbacks;

		QueryRequest(Display display, String query, Callbacks callbacks) {
			mQuery = query;
			mCallbacks = callbacks;
			mDisplay = display;
		}

		@Override
		public void run() {
			final String query = new String(mQuery);
			CloseableHttpClient httpclient = HttpClients.createDefault();
			HttpGet httpGet = new HttpGet(getQueryUrl(query));

			YouDaoResult result;
			try {
				result = httpclient.execute(httpGet, new YouDaoResponseHandler());

				if (result != null && result.getErrorCode() != YouDaoResult.ERROR_CODE_FAIL) {
					mCache.put(query, result);
				}

			} catch (IOException e) {
				result = null;
			} finally {
				try {
					httpclient.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			final YouDaoResult postResult = result;
			mDisplay.asyncExec(new Runnable() {
				public void run() {
					if (mCallbacks != null) {
						mCallbacks.onHandlQuery(query, postResult);
					}
				}
			});

		}

	}

	private final class YouDaoResponseHandler implements ResponseHandler<YouDaoResult> {

		@Override
		public YouDaoResult handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
			int status = response.getStatusLine().getStatusCode();
			if (status >= 200 && status < 300) {
				HttpEntity entity = response.getEntity();
				if (entity == null)
					return null;

				String json = EntityUtils.toString(entity);

				System.out.println(json);

				return JsonHelper.getYouDaoResultEntity(json);
			} else {
				throw new ClientProtocolException("Unexpected response status: " + status);
			}
		}

	}

	public static String getQueryUrl(String query) {
		try {
			return BasicURL + URLEncoder.encode(query, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		return "";
	}

	public static interface Callbacks {
		public void onHandlQuery(String query, YouDaoResult result);
	}

}
